﻿#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<vector>
using namespace std;

//class Person
//{
//public:
//	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
//	void identity()
//	{
//		cout << "void identity()" << _name << endl;
//	}
//protected:
//	string _name = "张三"; // 姓名
//	string _address; // 地址
//	string _tel; // 电话
//	int _age = 18; // 年龄
//};
//
//class Student : public Person
//{
//public:
//	// 学习
//	void study()
//	{
//		// ...
//	}
//protected:
//	int _stuid; // 学号
//};
//
//class Teacher : public Person
//{
//public:
//	// 授课
//	void teaching()
//	{
//		//...
//	}
//protected:
//	string title; // 职称
//};

// 实例演⽰三种继承关系下基类成员的各类型成员访问关系的变化
class Person
{
public:
	void Print()
	{
		cout << _name << endl;
	}
protected:
	string _name; // 姓名
private:
	int _age; // 年龄
};

//class Student : protected Person

//class Student : private Person

//class Student : public Person
//{
//protected:
//	int _stunum; // 学号
//};
//
//int main()
//{
//	//Student s;
//	//Teacher t;
//	//s.identity();
//	//t.identity();
//	return 0;
//}


namespace zyb
{
	//template<class T>
	//class vector
	//{};

	// stack和vector的关系，既符合is-a，也符合has-a
	template<class T>
	class stack : public vector<T>
	{
	public:
		void push(const T& x)
		{
			// 基类是类模板时，需要指定⼀下类域，
			// 否则编译报错:error C3861: “push_back”: 找不到标识符
			// 因为stack<int>实例化时，也实例化vector<int>了
			// 但是模版是按需实例化，vector<T>的push_back等成员函数未实例化，所以找不到
			vector<T>::push_back(x);
		}
		void pop()
		{
			vector<T>::pop_back();
		}
		const T& top()
		{
			return vector<T>::back();
		}
		bool empty()
		{
			return vector<T>::empty();
		}
	};
}

class Person
{
protected:
	string _name; // 姓名
	string _sex; // 性别
	int _age; // 年龄
};

class Student : public Person
{
public:
	int _No; // 学号
};

//int main()
//{
//	Student sobj;
//	// 1.派生类对象可以赋值给基类的指针/引用
//	Person* pp = &sobj;
//	Person& rp = sobj;
//	// 派生类对象可以赋值给基类的对象是通过调用基类的拷贝构造完成的
//	Person pobj = sobj;
//	//2.基类对象不能赋值给派生类对象，这里会编译报错
//	sobj = pobj;
//	return 0;
//}
//
//int main()
//{
//	return 0;
//}

// Student的_num和Person的_num构成隐藏关系，可以看出这样代码虽然能跑，但是非常容易混淆
class Person
{
protected:
	string _name = "小李子"; // 姓名
	int _num = 111; // 身份证号
};

class Student : public Person
{
public:
	void Print()
	{
		cout << " 姓名:" << _name << endl;
		cout << " 身份证号:" << Person::_num << endl;
		cout << " 学号:" << _num << endl;
	}
protected:
	int _num = 999; // 学号
};

//int main()
//{
//	Student s1;
//	s1.Print();
//	return 0;
//};

class A
{
public:
	void fun()
	{
		cout << "func()" << endl;
	}
};
class B : public A
{
public:
	void fun(int i)
	{
		cout << "func(int i)" << i << endl;
	}
};
//int main()
//{
//	B b;
//	b.fun(10);
//	b.fun();
//	return 0;
//};

class Student;
class Person
{
public:
	friend void Display(const Person& p, const Student& s);
protected:
	string _name; // 姓名
};
class Student : public Person
{
protected:
	int _stuNum; // 学号
};
void Display(const Person& p, const Student& s)
{
	cout << p._name << endl;
	cout << s._stuNum << endl;
}
int main()
{
	Person p;
	Student s;
	// 编译报错：error C2248: “Student::_stuNum”: 无法访问 protected 成员
	// 解决方案：Display也变成Student 的友元即可
	Display(p, s);
	return 0;
}

class Person
{
public:
	string _name;
	static int _count;
};
int Person::_count = 0;

class Student : public Person
{
protected:
	int _stuNum;
};
int main()
{
	Person p;
	Student s;
	// 这里的运行结果可以看到非静态成员_name的地址是不一样的
	// 说明派生类继承下来了，⽗派生类对象各有一份
	cout << &p._name << endl;
	cout << &s._name << endl;
	// 这里的运行结果可以看到静态成员_count的地址是一样的
	// 说明派生类和基类共用同一份静态成员
	cout << &p._count << endl;
	cout << &s._count << endl;
	// 公有的情况下，基类和派生类指定类域都可以访问静态成员
	cout << Person::_count << endl;
	cout << Student::_count << endl;
	return 0;
}

class Person
{
public:
	string _name; // 姓名
	/*int _tel;int _age;
string _gender;
string _address;*/
// ...
};

// 虚继承Person类
class Student : virtual public Person
{
protected:
	int _num; //学号
};

// 虚继承Person类
class Teacher : virtual public Person
{
protected:
	int _id; // 职工编号
};

// 教授助理
class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};

int main()
{
	// 使用虚继承，可以解决数据冗余和二义性
	Assistant a;
	a._name = "peter";
	return 0;
}

class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main()
{
	Derive d;
	Base1* p1 = &d;
	Base2* p2 = &d;
	Derive* p3 = &d;
	return 0;
}